package com.hospes.rmes.core;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;

import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.concurrent.ConcurrentHashMap;

public class ImageDownloader {

	private static final int HARD_CACHE_CAPACITY = 10;
	private static final int DELAY_BEFORE_PURGE = 5 * 1000;

	private final static ConcurrentHashMap<Object, SoftReference<Bitmap>> _softBitmapCache = new ConcurrentHashMap<Object, SoftReference<Bitmap>>(HARD_CACHE_CAPACITY / 2);
	private final Handler _purgeHandler = new Handler();

	private NetworkService _networkService;

	public ImageDownloader(NetworkService networkService) {
		_networkService = networkService;
	}

	public void cancelDownload(ImageView imageView) {
		BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
		if (bitmapDownloaderTask != null) {
			bitmapDownloaderTask.cancel(true);
		}
	}

	private void clear() {
		Thread splashTread = new Thread() {
			@Override
			public void run() {
				clearCache();
			}
		};
		splashTread.start();
	}

	public void download(ImageDescriptor image, ImageView imageView, ProgressBar progressBar) {
		resetPurgeTimer();
		Bitmap bitmap = getBitmapFromCache(image);
		imageView.setVisibility(View.GONE);
		progressBar.setVisibility(View.VISIBLE);
		if (bitmap == null || bitmap.isRecycled()) {
			forceDownload(image, imageView, progressBar);
		} else {
			cancelPotentialDownload(image, imageView);
			imageView.setImageBitmap(bitmap);
			imageView.setVisibility(View.VISIBLE);
			progressBar.setVisibility(View.GONE);
		}
	}

	public void clearCache() {
		Log.w("MEMORY", "Clearing memory cache");
		_hardBitmapCache.clear();
		_softBitmapCache.clear();
		_networkService.getClient().getConnectionManager().closeExpiredConnections();
		System.gc();
	}

	private Bitmap downloadBitmap(ImageDescriptor image) {
		return _networkService.downloadImage(image);
	}

	private void forceDownload(ImageDescriptor image, ImageView imageView, ProgressBar progressBar) {
		if (image.imageId == null) {
			imageView.setImageDrawable(null);
			return;
		}
		if (cancelPotentialDownload(image, imageView)) {
			BitmapDownloaderTask task = new BitmapDownloaderTask(imageView, progressBar);
			DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
			imageView.setImageDrawable(downloadedDrawable);
			task.execute(image);
		}
	}

	private void addBitmapToCache(ImageDescriptor image, Bitmap bitmap) {
		if (bitmap != null) {
			synchronized (_hardBitmapCache) {
				_hardBitmapCache.put(image, bitmap);
			}
		}
	}

	private Bitmap getBitmapFromCache(ImageDescriptor image) {
		synchronized (_hardBitmapCache) {
			final Bitmap bitmap = _hardBitmapCache.get(image);
			if (bitmap != null) {
				_hardBitmapCache.remove(image);
				_hardBitmapCache.put(image, bitmap);
				return bitmap;
			}
		}

		SoftReference<Bitmap> bitmapReference = _softBitmapCache.get(image);
		if (bitmapReference != null) {
			final Bitmap bitmap = bitmapReference.get();
			if (bitmap != null) {
				return bitmap;
			} else {
				_softBitmapCache.remove(image);
			}
		}
		return null;
	}

	private void resetPurgeTimer() {
		_purgeHandler.removeCallbacks(_purger);
		_purgeHandler.postDelayed(_purger, DELAY_BEFORE_PURGE);
	}

	private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) {
		if (imageView != null) {
			Drawable drawable = imageView.getDrawable();
			if (drawable instanceof DownloadedDrawable) {
				DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable;
				return downloadedDrawable.getBitmapDownloaderTask();
			}
		}
		return null;
	}

	private static boolean cancelPotentialDownload(ImageDescriptor image, ImageView imageView) {
		BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
		if (bitmapDownloaderTask != null) {
			ImageDescriptor imageDescriptor = bitmapDownloaderTask._image;
			if ((imageDescriptor == null) || (!imageDescriptor.equals(image))) {
				bitmapDownloaderTask.cancel(true);
			} else {
				return false;
			}
		}
		return true;

	}

	private class BitmapDownloaderTask extends AsyncTask<ImageDescriptor, Void, Bitmap> {
		private ImageDescriptor _image;
		private final WeakReference<ImageView> _imageViewReference;
		private final WeakReference<ProgressBar> _progressBarReference;

		public BitmapDownloaderTask(ImageView imageView, ProgressBar progressBar) {
			_imageViewReference = new WeakReference<ImageView>(imageView);
			_progressBarReference = new WeakReference<ProgressBar>(progressBar);
		}

		@Override
		protected Bitmap doInBackground(ImageDescriptor... params) {
			_image = params[0];
			return downloadBitmap(_image);
		}

		@Override
		protected void onPostExecute(Bitmap bitmap) {
			if (isCancelled()) {
				bitmap = null;
			}
			addBitmapToCache(_image, bitmap);
			if (_imageViewReference != null && _progressBarReference != null) {
				ImageView imageView = _imageViewReference.get();
				ProgressBar progressBar = _progressBarReference.get();
				if (bitmap != null && !bitmap.isRecycled() && imageView != null) {
					imageView.setImageBitmap(bitmap);
					imageView.setVisibility(View.VISIBLE);
					progressBar.setVisibility(View.GONE);
				} else {
					if (!isCancelled() && bitmap == null && imageView != null) {
						Log.w("", "IMAGE NOT LOADED");
						clear();
						imageView.setImageDrawable(null);
						imageView.setVisibility(View.GONE);
						progressBar.setVisibility(View.VISIBLE);
						ImageDownloader.this.download(_image, imageView, progressBar);
					}
				}
			}
		}
	}

	private static class DownloadedDrawable extends ColorDrawable {
		private final WeakReference<BitmapDownloaderTask> _bitmapDownloaderTaskReference;

		public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
			super(Color.WHITE);
			_bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
		}

		public BitmapDownloaderTask getBitmapDownloaderTask() {
			return _bitmapDownloaderTaskReference.get();
		}
	}

	private final HashMap<Object, Bitmap> _hardBitmapCache = new LinkedHashMap<Object, Bitmap>(HARD_CACHE_CAPACITY / 2, 0.75f, true) {

		private static final long serialVersionUID = 4332515555299501360L;

		@Override
		protected boolean removeEldestEntry(Entry<Object, Bitmap> objectBitmapEntry) {
			if (size() > HARD_CACHE_CAPACITY) {
				_softBitmapCache.put(objectBitmapEntry.getKey(), new SoftReference<Bitmap>(objectBitmapEntry.getValue()));
				return true;
			} else
				return false;
		}
	};

	private final Runnable _purger = new Runnable() {
		public void run() {
			Log.w("memory", "kagbe clear CHACE");
			clearCache();
		}
	};
}
